import React, { useContext, useReducer } from 'react';
import PropTypes from 'prop-types';
import { Select, Input } from 'antd';
import { useDeepCompareEffect } from 'ahooks';
import get from 'lodash/get';
import omit from 'lodash/omit';
import isPlainObject from 'lodash/isPlainObject';
import Expression from '../Expression';
import { ASSERT_ALL, ASSERT_ONE, CONDITION_2, CONDITION_CUSTOM } from '../../settings';
import Context from '@/pages/Transformer/components/SourcePanel/context';

const { Option } = Select;

const initialState = {
  visible: false,
  dataSource: [],
  value: [],
};

function reducer(state, action) {
  const { type, payload } = action;

  if (type === 'sync_props') {
    return {
      ...state,
      ...payload,
    };
  }

  if (type === 'change_value') {
    return {
      ...state,
      value: { ...state.value, ...payload },
    };
  }

  throw new Error();
}

function Rule({
  value = {},
  disabled = false,
  readOnly = false,
  onChange,
  treeData,
  asserts = [],

  className = '',
  style = {},
  mode = 'select',
}) {
  const [state, dispatch] = useReducer(reducer, initialState);
  useDeepCompareEffect(() => {
    const data = {};

    if (isPlainObject(value)) {
      data.value = value;
    }

    if (Object.keys(data).length > 0) {
      dispatch({ type: 'sync_props', payload: data });
    }
  }, [value]);

  return (
    <div>
      <Select
        placeholder="匹配模式"
        value={get(state, 'value.type') || get(asserts, '[0].value')}
        onChange={value => {
          dispatch({ type: 'change_value', payload: { type: value } });
          onChange({ ...state.value, type: value });
        }}
        disabled={disabled}
        readOnly={readOnly}
        style={{ width: 90, marginRight: 4 }}
      >
        {asserts.map(k => (
          <Option key={k.value} value={k.value}>
            {k.title}
          </Option>
        ))}
      </Select>
      <div
        style={{ width: 'calc(100% - 90px - 4px)', display: 'inline-block', verticalAlign: 'top' }}
      >
        {get(state, 'value.condition.type') === CONDITION_2 ? (
          <Expression
            treeData={treeData}
            value={omit(get(state, 'value.condition'), ['type']) || []}
            className={className}
            style={style}
            allowClear
            readOnly={readOnly}
            disabled={disabled}
            mode={mode}
            onChange={value => {
              dispatch({
                type: 'change_value',
                payload: { condition: { type: CONDITION_2, ...value } },
              });
              onChange({ ...state.value, condition: { type: CONDITION_2, ...value } });
            }}
          />
        ) : (
          <Input
            value={get(state, 'value.condition.expression')}
            placeholder="自定义条件"
            allowClear
            readOnly={readOnly}
            disabled={disabled}
            onChange={e => {
              dispatch({
                type: 'change_value',
                payload: { condition: { type: CONDITION_CUSTOM, expression: e.target.value } },
              });
              onChange({
                ...state.value,
                condition: { type: CONDITION_CUSTOM, expression: e.target.value },
              });
            }}
          />
        )}
      </div>
    </div>
  );
}

Rule.propTypes = {
  value: PropTypes.shape({
    type: PropTypes.oneOf([ASSERT_ONE, ASSERT_ALL]),
    condition: PropTypes.shape({
      type: PropTypes.oneOf([CONDITION_2, CONDITION_CUSTOM]),
      lhsPath: PropTypes.arrayOf(PropTypes.string),
      op: PropTypes.string,
      rhs: PropTypes.shape({
        isString: PropTypes.bool,
        stringValue: PropTypes.string,
      }),
    }),
  }),
  onChange: PropTypes.func,
  className: PropTypes.string,
  disabled: PropTypes.bool,
  readOnly: PropTypes.bool,
  style: PropTypes.object,
};

Rule.defaultProps = {
  value: {
    type: ASSERT_ONE, // 元素断定
    condition: {
      type: CONDITION_2,
      lhsPath: [],
      op: 'eq',
    },
  },
  onChange: () => {},
  className: '',
  readOnly: false,
  disabled: false,
  style: {},
};

export default Rule;
